#pragma once

#include <QString>
#include <QIcon>
#include <QUuid>
#include <QTime>
#include <QPixmap>
#include <QPainter>
#include <QPainterPath>
#include <QFile>
#include <QHBoxLayout>
#include <QLineEdit>
#include <QToolButton>
#include <QScrollArea>
#include <QScrollBar>
#include <QDebug>
#include <QFileInfo>

#include "base.qpb.h"
#include "gateway.qpb.h"
#include "user.qpb.h"
#include "file.qpb.h"
#include "friend.qpb.h"
#include "notify.qpb.h"
#include "speech_recognition.qpb.h"
#include "message_storage.qpb.h"
#include "message_transmit.qpb.h"

// 命名空间
namespace model{
/*------------------- 工具函数 -------------------*/
// 封装一个宏 打印日志
// 打印文件名和行号

// 从 __FILE__ 中提取文件名 -- 下面两种方式都可以 noquote() 是用于去掉 qdebug 自带 ""
static inline QString getFileName(const QString& path){
    QFileInfo fileInfo(path);
    return fileInfo.fileName();
}
#define __FILENAME__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
// #define LOG() qDebug().noquote() << "[" << model::getFileName(__FILE__) << ":" << __LINE__ << "]"

#define TAG QString("[%1:%2]").arg(model::getFileName(__FILE__), QString::number(__LINE__))
#define LOG() qDebug().noquote() << TAG


// 要求函数定义写在 .h 中, 必须加 static/inline, 避免链接阶段出现函数重定义问题
static inline QString formatTime(int64_t timestamp){ // 把时间戳转为标准时间
    QDateTime dateTime = QDateTime::fromSecsSinceEpoch(timestamp);
    return dateTime.toString("MM-dd HH::mm::ss");
}

// 获取时间戳
static inline int64_t getTime(){
    return QDateTime::currentSecsSinceEpoch();
}

// 根据 QByteArray 转成 QIcon
static inline QIcon makeIcon(const QByteArray& byteArray){
    QPixmap pixmap;
    pixmap.loadFromData(byteArray);
    QIcon icon(pixmap);
    return icon;
}

// 读写文件 -- 从指定文件读取所有二进制内容得到 QByteArray
static inline QByteArray loadFileToByteArray(const QString& path){
    QFile file(path);
    bool ok = file.open(QFile::ReadOnly);
    if(!ok){
        qDebug() << "文件打开失败";
        return QByteArray();
    }
    QByteArray content = file.readAll();
    file.close();
    return content;
}

// 把 QByteArray 的内容写入指定文件
static inline void writeByteArrayToFile(const QString& path, const QByteArray& content){
    QFile file(path);
    bool ok = file.open(QFile::WriteOnly);
    if(!ok){
        qDebug() << "文件打开失败";
        return ;
    }
    file.write(content);
    file.flush();
    file.close();
}

// 转为圆角头像
static inline QPixmap getRoundRectPixmap(QPixmap srcPixMap, const QSize & size, int radius){
    // 不处理空数据或者错误数据
    if (srcPixMap.isNull()) return srcPixMap;

    // 获取图片尺寸
    int imageWidth = size.width(), imageHeight = size.height();

    // 处理大尺寸的图片,保证图片显示区域完整
    QPixmap newPixMap = srcPixMap.scaled(imageWidth, (imageHeight == 0 ? imageWidth : imageHeight),Qt::IgnoreAspectRatio, Qt::SmoothTransformation);

    QPixmap destImage(imageWidth, imageHeight);
    destImage.fill(Qt::transparent);
    QPainter painter(&destImage);
    // 抗锯齿
    painter.setRenderHints(QPainter::Antialiasing, true);
    // 图片平滑处理
    painter.setRenderHints(QPainter::SmoothPixmapTransform, true);
    // 将图片裁剪为圆角
    QPainterPath path;
    QRect rect(0, 0, imageWidth, imageHeight);
    path.addRoundedRect(rect, radius, radius);
    painter.setClipPath(path);
    painter.drawPixmap(0, 0, imageWidth, imageHeight, newPixMap);

    return destImage;
}


static inline QPixmap getRoundPixmap(QPixmap srcPixMap, const QSize & size)
{
    // 不处理空数据或者错误数据
    if (srcPixMap.isNull()) return srcPixMap;

    // 获取图片尺寸
    int imageWidth = size.width(), imageHeight = size.height();
    QPixmap roundedAvatar(size); // 根据 avatarBtn 的大小
    roundedAvatar.fill(Qt::transparent);

    QPainter avatarPainter(&roundedAvatar);
    avatarPainter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
    QPainterPath avatarPath;
    avatarPath.addRoundedRect(roundedAvatar.rect(), imageWidth / 2, imageHeight / 2);
    avatarPainter.setClipPath(avatarPath);
    // 关键修改：使用 Qt::KeepAspectRatio 模式，确保图片完整显示
    avatarPainter.drawPixmap(0, 0, imageWidth, imageHeight, srcPixMap.scaled(imageWidth, imageHeight, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation));
    avatarPainter.end();

    return roundedAvatar;
}

// 搜索栏
static inline QLineEdit* createSearchBox(int height, const QString& placeholderText, int fontSize)
{
    QLineEdit* searchEdit = new QLineEdit();
    searchEdit->setPlaceholderText(placeholderText);
    searchEdit->setFixedHeight(height);

    // 使用样式表直接设置图标大小
    QString style = QString(R"(
        QLineEdit {
            border-radius: 5px;
            background-color: #EAEAEA;
            padding-left: 4px;
            border: 1px solid transparent;
            font-size: %1px;
        }
        QLineEdit:focus {
            background-color: #FFFFFF;
            border: 1px solid #07c160;
        }
    )").arg(fontSize);
    searchEdit->setStyleSheet(style);

    // 计算图标大小（基于行编辑框高度）
    int iconSize = height * 0.6;

    // 方式一: 添加搜索图标
    // QPixmap pixmap(":/resource/image/search.png");
    // pixmap = pixmap.scaled(iconSize, iconSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
    // QAction* searchAction = searchEdit->addAction(pixmap,QLineEdit::LeadingPosition);
    // // 这行通常用来防止图标在上下文菜单中可见，与缩放无关，但通常保留
    // searchAction->setIconVisibleInMenu(false);

    // 方式二: 添加搜索图标
    QToolButton* iconButton = new QToolButton(searchEdit);
    iconButton->setIcon(QIcon(":/resource/image/search.png"));
    iconButton->setIconSize(QSize(iconSize, iconSize));
    iconButton->setStyleSheet("border: none; background: transparent;");

    // 使用布局将按钮嵌入行编辑框
    QHBoxLayout* layout = new QHBoxLayout(searchEdit);
    layout->addWidget(iconButton);
    layout->addStretch();
    layout->setContentsMargins(4, 0, 4, 0); // 内边距

    // 调整文本边距
    searchEdit->setTextMargins(iconSize + 8, 0, 0, 0);

    return searchEdit;
}


// 滚动条
static inline QScrollArea* createScrollArea()
{
    QScrollArea* scrollArea = new QScrollArea();
    scrollArea->setWidgetResizable(true);
    scrollArea->setFrameShape(QFrame::NoFrame);
    scrollArea->setStyleSheet("QScrollArea { border: none; background-color: transparent;}");
    scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);

    // 垂直滚动条样式
    scrollArea->horizontalScrollBar()->setStyleSheet(R"( QScrollBar:horizontal { height: 0px; } )");
    scrollArea->verticalScrollBar()->setStyleSheet(R"(
        QScrollBar:vertical {
            width: 8px;
            background: transparent;
            margin: 0;
        }
        QScrollBar::handle:vertical {
            background: rgba(150, 150, 150, 180);
            min-height: 20px;
            border-radius: 3px;
        }
        QScrollBar::handle:vertical:hover { background: rgba(120, 120, 120, 200); }
        QScrollBar::handle:vertical:pressed { background: rgba(80, 80, 80, 255); }
        QScrollBar::add-line, QScrollBar::sub-line,
        QScrollBar::add-page, QScrollBar::sub-page {
            background: none;
            width: 0;
            height: 0;
        }
    )");

    return scrollArea;
}

// 文本输入框
static QLineEdit* createLineEdit(const QIcon &icon, const QString &placeholderText){
    QLineEdit* lineEdit = new QLineEdit();
    lineEdit->setPlaceholderText(placeholderText);
    lineEdit->setFixedHeight(40);
    lineEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);

    // 使用样式表直接设置图标大小
    QString style = QString(R"(
        QLineEdit {
            border-radius: 5px;
            background-color: #EAEAEA;
            padding-left: 4px;
            border: 1px solid transparent;
            font-size: 12px;
        }
        QLineEdit:focus {
            background-color: #FFFFFF;
            border: 1px solid #07c160;
        }
    )");
    lineEdit->setStyleSheet(style);

    // 添加图标
    QAction* searchAction = lineEdit->addAction(icon, QLineEdit::LeadingPosition);
    searchAction->setIconVisibleInMenu(false); // 防止图标在上下文菜单中可见

    return lineEdit;
}

/*------------------- 用户信息 -------------------*/
class UserInfo{
public:
    // 这里使用字符串作为 id, 生成更灵活, 毕竟分布式系统需要针对用户消息分库分表, 就无法整数自增主键
    // 后面可以通过 uuid / 雪花算法 来生成唯一主键
    QString userId = "";        // 用户编号
    QString nickname = "";      // 用户昵称
    QString description = "";   // 用户签名
    QString phone = "";         // 用户号码
    QIcon avatar;               // 用户头像

    // 把 protobuf 中的 UserInfo 对象转成当前对象的 UserInfo 对象
    void load(const bite_im::UserInfo& userInfo){
        this->userId = userInfo.userId();
        this->nickname = userInfo.nickname();
        this->phone = userInfo.phone();
        this->description = userInfo.description();
        if (userInfo.avatar().isEmpty()) {
            // 使用默认头像即可
            this->avatar = QIcon(":/resource/image/robot.png");
        } else {
            this->avatar = makeIcon(userInfo.avatar());
        }
    }
};


/*------------------- 消息信息 -------------------*/
enum MessageType{
    TEXT_TYPE,      // 文本消息
    IMAGE_TYPE,     // 图片消息
    FILE_TYPE,      // 文件消息
    SPEECH_TYPE     // 语言消息  
};


class Message{
public:
    QString messageId = "";             // 消息编号
    QString chatSessionId = "";         // 消息所属会话编号
    QString time = "";                  // 消息时间, 通过 格式化 的方式表示 07-21 18:29:01
    MessageType messageType = TEXT_TYPE;        // 消息类型
    UserInfo sender;                    // 发送者消息
    QByteArray content;                 // 消息正文内容
    QString fileId = "";                // 文件身份标识 -- 当消息类型为 文件/图片/语音时生效, 否则为 ""
    QString fileName = "";              // 文件名称 -- 当消息类型为 文件/语音时生效, 否则为 ""

    // 此处 extraInfo 目前只是在消息类型为文件消息时, 作为 "文件名" 补充.
    static Message makeMessage(MessageType messageType, const QString& chatSessionId, const UserInfo& sender,
                                const QByteArray& content, const QString& extraInfo)
    {
        if(messageType == TEXT_TYPE){
            return makeTextMessage(chatSessionId, sender, content);
        }else if(messageType == IMAGE_TYPE){
            return makeImageMessage(chatSessionId, sender, content);
        }else if(messageType == FILE_TYPE){
            return makeFileMessage(chatSessionId, sender, content, extraInfo);
        }else if(messageType == SPEECH_TYPE){
            return makeSpeechMessage(chatSessionId, sender, content);
        }else{
            return Message(); // 未知消息类型
        }
    }

    void load(const bite_im::MessageInfo& messageInfo) {
        this->messageId = messageInfo.messageId();
        this->chatSessionId = messageInfo.chatSessionId();
        this->time = formatTime(messageInfo.timestamp());
        this->sender.load(messageInfo.sender());

        // 设置消息类型
        auto type = messageInfo.message().messageType();
        if (type == bite_im::MessageTypeGadget::MessageType::STRING) {
            this->messageType = TEXT_TYPE;
            this->content = messageInfo.message().stringMessage().content().toUtf8();
        } else if (type == bite_im::MessageTypeGadget::MessageType::IMAGE) {
            this->messageType = IMAGE_TYPE;
            if (messageInfo.message().imageMessage().hasImageContent()) {
                this->content = messageInfo.message().imageMessage().imageContent();
            }
            if (messageInfo.message().imageMessage().hasFileId()) {
                this->fileId = messageInfo.message().imageMessage().fileId();
            }
        } else if (type == bite_im::MessageTypeGadget::MessageType::FILE) {
            this->messageType = FILE_TYPE;
            if (messageInfo.message().fileMessage().hasFileContents()) {
                this->content = messageInfo.message().fileMessage().fileContents();
            }
            if (messageInfo.message().fileMessage().hasFileId()) {
                this->fileId = messageInfo.message().fileMessage().fileId();
            }
            this->fileName = messageInfo.message().fileMessage().fileName();
        } else if (type == bite_im::MessageTypeGadget::MessageType::SPEECH) {
            this->messageType = SPEECH_TYPE;
            if (messageInfo.message().speechMessage().hasFileContents()) {
                this->content = messageInfo.message().speechMessage().fileContents();
            }
            if (messageInfo.message().speechMessage().hasFileId()) {
                this->fileId = messageInfo.message().speechMessage().fileId();
            }
        } else {
            // 错误的类型, 啥都不做了, 只是打印一个日志
            LOG() << "非法的消息类型! type=" << type;
        }
    }

private:
    // 生成唯一 id
    static QString makeId(){
        // return QUuid::createUuid().toString();
        return "M" +  QUuid::createUuid().toString().sliced(25, 12);
    }

    static Message makeTextMessage(const QString& chatSessionId, const UserInfo& sender,const QByteArray& content){
        Message message;
        message.messageId = makeId();
        message.chatSessionId = chatSessionId;
        message.sender = sender;
        message.time = formatTime(getTime());
        message.content = content;
        message.messageType = TEXT_TYPE;
        // 对于文本消息而言, 下面两个不使用
        message.fileId = "";
        message.fileName = "";
        return message;
    }

    static Message makeImageMessage(const QString& chatSessionId, const UserInfo& sender,const QByteArray& content){
        Message message;
        message.messageId = makeId();
        message.chatSessionId = chatSessionId;
        message.sender = sender;
        message.time = formatTime(getTime());
        message.content = content;
        message.messageType = IMAGE_TYPE;

        message.fileId = "";
        message.fileName = "";
        return message;
    }
    static Message makeFileMessage(const QString& chatSessionId, const UserInfo& sender,const QByteArray& content, const QString& filename){
        Message message;
        message.messageId = makeId();
        message.chatSessionId = chatSessionId;
        message.sender = sender;
        message.time = formatTime(getTime());;
        message.content = content;
        message.messageType = FILE_TYPE;

        message.fileId = "";
        message.fileName = filename;
        return message;
    }
    static Message makeSpeechMessage(const QString& chatSessionId, const UserInfo& sender,const QByteArray& content){
        Message message;
        message.messageId = makeId();
        message.chatSessionId = chatSessionId;
        message.sender = sender;
        message.time = formatTime(getTime());;
        message.content = content;
        message.messageType = TEXT_TYPE;

        message.fileId = "";
        message.fileName = "";
        return message;
    }
};

/*------------------- 会话信息 -------------------*/
class ChatSessionInfo{
public:
    QString chatSessionId = "";     // 会话编号
    QString chatSessionName = "";   // 会话名字 单聊: 对方昵称名 群聊: 群名
    Message lastMessage;            // 表示最新消息
    QIcon avatar;                   // 会话头像
    QString userId = "";

    void load(const bite_im::ChatSessionInfo& chatSessionInfo) {
        this->chatSessionId = chatSessionInfo.chatSessionId();
        this->chatSessionName = chatSessionInfo.chatSessionName();
        if (chatSessionInfo.hasSingleChatFriendId()) {
            this->userId = chatSessionInfo.singleChatFriendId();
        }
        if (chatSessionInfo.hasPrevMessage()) {
            lastMessage.load(chatSessionInfo.prevMessage());
        }
        if (chatSessionInfo.hasAvatar() && !chatSessionInfo.avatar().isEmpty()) {
            // 已经有头像了, 直接设置这个头像
            this->avatar = makeIcon(chatSessionInfo.avatar());
        } else {
            // 如果没有头像, 则根据当前会话是单聊还是群聊, 使用不同的默认头像.
            if (userId != "") {
                // 单聊
                this->avatar = QIcon(":/resource/image/girl.png");
            } else {
                // 群聊
                this->avatar = QIcon(":/resource/image/groupAvatar.png");
            }
        }
    }
};

} // end model



















